/*  _________________________________________
   /                                      /_ \
  |             Scene Types              |/ \ |
  |                                      |___||
   \______________________________________\_/ |
       |                                      |
      /     Scene Type Classes               /
     /     Written April, 2009              /
    |     by Darrell Eastman.              |___
    |                                      |   |
     \______________________________________\_/
*/

#include <irrlicht.h>
#include <iostream>
#include "AI.h"
#include "animation.h"

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace std;

ISceneManager*		smgr = IrrlichtDevice::getSceneManager();		//* temp pointer
IrrlichtDevice*	device = IrrlichtDevice;							//* temp pointer
IEventReceiver*	receiver = IrrlichtDevice::getEventReceiver();	//* temp pointer






struct material
{
//Material Property
public:
	string		Nam;	//Material Name
	string		Snd;	//Sound Filename
		//Sand, Plant, Water, Glass, Wood, Rock, and Metal
	string		Tex[3];	//Texture Box
		//Floor, Edge, and Wall
		//VVV|---|---
		//>+<|>+<||+|
		//^^^|^^^|^^^
	string		Con;	//Condition
		//Rough, Dry, Hot, Shiny, Wet, and Cold
	particle	Dbs;	//Debris Effect
	
private:
	list		Cnt;	//Material Count
}

//~~~~~~~~~~~~~~~~~~~~ Map ~~~~~~~~~~~~~~~~~~~~~~
class map //: IShaderConstantSetCallBack
{
public:	
//Map Attributes
	IAnimatedMesh				BSP;	//Level BSP Map
	ITerrainSceneNode			Ter;	//Map Terrain SceneNode
	string						Hgtt;	//Terrain Height Map
	string						Dtl;	//Detail Map
	list						Mat;	//Terrain Material
	ISceneNode					Nde;	//Map SceneNode
	vector3df					Grv;	//Level Gravity
	ITriangleselector			Slc;	//Map Triangle Selector
	SLight						Lgt;	//Global Light Source
	float						scale;	//*
	float						scale2;	//*

	/*
	virtual void OnSetConstants( IMaterialRendererServices* services, s32 userData )
	{
		int		d[]	=
			{0, 1, 2, 3};		//Sampler2d IDs

		IVideoDriver*	VideoDriver		= services->getVideoDriver();
		matrix4			worldViewProj	= VideoDriver->getTransform( ETS_PROJECTION );			
		worldViewProj	*= VideoDriver->getTransform( ETS_VIEW );
		worldViewProj	*= VideoDriver->getTransform( ETS_WORLD );
		
		services->setVertexShaderConstant( "mat", worldViewProj.pointer(), 16 );
		services->setVertexShaderConstant( "SunPosPreT", &SunPos.X, 3 );
		services->setVertexShaderConstant( "MoonPosPreT", &MoonPos.X, 3 );
		services->setVertexShaderConstant( "max_sun_height", &MaxSunHeight, 1 );
		services->setPixelShaderConstant( "MaxD", &FarLink, 1 );
		services->setPixelShaderConstant( "s", &scale, 1 );
		services->setPixelShaderConstant( "s2", &scale2, 1 );
		services->setPixelShaderConstant( "sunDiffuse", &SunDiffuse.r, 4 );
		services->setPixelShaderConstant( "Tex", ( float* )&d[0], 1 );
		services->setPixelShaderConstant( "Tex2", ( float* )&d[1], 1 );
		*/
	}
private:
	list	Count;	//Map Count

	Update( map Map )
	{

		return 1;
	}
	Initialize( string MNam, string MBSP, vector3df MGrv, string MHgt, string MDtl, string MTex, ILightSceneNode MLgt, vector3df MSca )
	{
		map	M	= new map;
		ISceneUserDataSerializer*	mapdata;

		smgr->loadScene( "\media\map" + MapNam + ".irr", &mapdata );
		
		//Build BSP Mesh
		if( MBSP )
		{
			device->getFileSystem()->addZipFileArchive( "media\maps.pk3" );
			M.BSP	= smgr->getMesh( MBSP )->getMesh( 0 );	//Map Mesh
		}
		
		//Create Object Scene Types
		list	nodes	ISceneManager::getRootSceneNode().getChildren();
			//
		for each( list nodes; ISceneNode S )
		{
			IAttributes	Attrribute = S;
			ISceneNode::serializeAttributes();
			S.
		}

		//Terrain HeightMap
		if( MHgt )
		{
			M.Hgt	= MHgt;
			M.Ter	= smgr->addTerrainSceneNode(
				M.Hgt,									// heightmap
				0,										// parent node
				-1,										// node id
				vector3df( -100.f,    0.f, -100.f ),	// position
				vector3df(    0.f,    0.f,    0.f ),	// rotation
				vector3df(   40.f,    5.f,   40.f ),	// scale
				SColor( 255, 255, 255, 255 ),			// vertexColor
				5,										// maxLOD
				ETPS_17,								// patchSize
				4 );									// smoothFactor
			
			<s32>	DetailMap	= driver->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles( "./shaders/DTMV.glsl", "vertexMain", EVST_VS_2_0, "./shaders/DTMP.glsl", "pixelMain", EPST_PS_2_0, DTM, EMT_SOLID );
			M.Ter->setMaterialTexture( 0, driver->getTexture( Tex ));
			M.Ter->setMaterialTexture( 1, driver->getTexture( Dtl ));
			M.Ter->setMaterialType(( E_MATERIAL_TYPE )DetailMap );
			M.Ter->setMaterialFlag( EMF_LIGHTING, false );
			M.Ter->getMaterial( 0 ).AmbientColor = SColor( 255, 55, 55, 55 );
			M.Ter->scaleTexture( 1.0f, 20.0f );
		}

		//Include Global Light Source
		M.Lgt.Type = ELT_DIRECTIONAL;//Light Type
		ILightSceneNode::setLightData( M.Lgt );

		//Paint Terrain Material

		//Check Each Node Type
		if( M.BSP.IsValid())
			M.Nde	= smgr->addOctTreeSceneNode( MBSP.getMesh( 0 ));


		if( M.Nde.IsValid())
		{
			M.Nde.SetPosition( vector3df( 0, 0, 0 ));

			M.Slc	= smgr->createOctTreeTriangleselector( M.BSP.getMesh( 0 ), M.Nde, 128 );
			M.Nde.setTriangleselector( M.Slc );
		}
		for each( void T; list MTyp )
		{
			switch ( type_info::name( T ))
			{
				case "backdrop";
					T = ISceneNode( T );
					backdrop::Create( T, T.Nam,
					break;

			return 0;
		}

		return 1;
	}
};

//~~~~~~~~~~~~~~~~ Scene Types ~~~~~~~~~~~~~~~~~~
class user
{
public:
	//User						UsrObj;				//User Object
	IAnimatedMesh				Msh;				//User Mesh
	IAnimatedMeshSceneNode	Nde;				//User Scenenode
	vector3df					Elp;				//User Collision Ellipsoid
	ITexture					Skn;				//User Skin Texture
	vector3df					Vel;				//User Velocity
	float						Mmt;				//User Momentum
	float						Fct;				//User Friction	
	string						Ipt;				//User Input Key, Joy, Net
	joystick					Joy;				//User Joystick
	vector2df					ConDir;				//Direction of Joystick
	float						ConSpd;				//Extent of Joystick
	vector3df					Dsp;				//Displacement from Last Position
	vector3df					LasLasPos;			//Last Last Position
	vector3df					LasPos;				//Last Position
	string						Ste;				//Primary User State
	string						Evt;				//Secondary User State
	int							EvtTim;  			//Event Timer Ms
	float						Hth;				//User Health
	float						Stm;				//User Stamina
	int							Kil;				//User Kills
	string						Nam;				//User Name
	string						Wpn;				//User Weapon Name, selected Weapon Slot
	string						Itm;				//User Item Name, selected Item Slot
	int							Ani;				//User Animation
	int							AniLas;				//Last Animation Frame
	int							AniInf[2][14]	=	//Animation Info Table
		// Stnd| Walk|	Run| Jump| Flip| Sprn| Leap| Crwl| Crch| Clmb| Hi-5| Fall| Impt|  Die| Dead| Voic|
		{{    1,   42,    1,  120,   89,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0}, //Start
		{    41,   88,    1,  153,  119,    0,    0,    0,    0,    0,	  0,    0,    0,    0,    0}};//End
	int							Bmp;				//Bumping Collision Flag
	int							SprTim;				//Spring Timer
	int							Lnd;				//Landing Collision Flag
	triangle3df				Tri;				//Collision Result Triangle
	//Void ObjArr[5, 5, 0]							//Object Array
	//	IntObj | ActObj | VisObj | SlcObj | Obj
	//	-------|--------|--------|--------|-------
	//0|Ent    |Ent  	|Ent	 |Ent	  |Ent
	//1|Prp    |Prp  	|Prp	 |Prp	  |Prp
	//2|Bak    |Bak  	|Bak	 |Bak	  |Bak
	//3|Clc    |Clc  	|Clc	 |Clc	  |Clc
	//4|Prj    |Prj  	|Prj	 |Prj	  |Prj
	list						IntObj;				//Interactive Objects
	list						ActObj;				//Active Objects
	list						VisObj;				//Visible Objects
	list						InaObj;				//Inactive Objects
	list						SlcObj;				//Selected Objects

	Update()
	{
		switch( Ste );
		{
			case "Stand":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}	
					//Elapse Event Animation
					else
					{
						AniLas = Nde.getFrameNr();
						EvtTim -= 1000 / LastFPS;
					}
				}
				if( Mmt > 0 ) Mmt -= 0.25;	//Set Momentum to null
				
				//Animation
				if( Evt )
				{
					if( Ani )
					{
						Ani	= 0;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				if( Vel.getX() && Vel.getZ()) this.Land( 0.25 );
				this.Collide();
				
				//Sound
				break;

			case "Walk":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
						
					//Elapse Event Animation
					 
						AniLas = Nde.getFrameNr();
						EvtTim -= 1000 / LastFPS;
					}
				}
				if( receiver.IsKeyDownUp( EKEY_KEY_W ) ||
					receiver.IsKeyDownUp( EKEY_KEY_S ) ||
					receiver.IsKeyDownUp( EKEY_KEY_A ) ||
					receiver.IsKeyDownUp( EKEY_KEY_D ))
				{
					Ste	= "Stand";
				}
				else if( Mmt <= 3.5 )				//Increase Speed of User
				{
					if( Mmt < 3.5 ) Mmt += 0.25;	//Increase Momentum
				}
				
				//Animation
				if( Evt )
				{
					if( Ani ! 1 )
					{
						Ani = 1;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Move( Mmt );
				this.Collide();
				
				//Sound
				break;

			case "Run":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( receiver.IsKeyDownUp( EKEY_KEY_W ) ||
					receiver.IsKeyDownUp( EKEY_KEY_S ) ||
					receiver.IsKeyDownUp( EKEY_KEY_A ) ||
					receiver.IsKeyDownUp( EKEY_KEY_D ))
				{
					Ste	= "Stand";
				}
				else if( receiver.IsKeyDownUp( EKEY_SHIFT ))
				{
					Ste	= "Walk";
				}
				else if( Mmt <= 5)	//Increase Speed of User
				{
					if( Mmt < 5 ) Mmt += 0.25;	//Increase Momentum
				}
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 2 )
					{
						Ani	= 2;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Move( Mmt );
				this.Collide();
				
				//Sound
				break;

			case "Crouch":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}	
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( receiver.IsKeyDownUp( EKEY_CONTROL ))
				{
					Ste = "Stand";
				}
				else if( Mmt )
				{
					if( Mmt < 0 ) Mmt = 0;		//Set Momentum to null
					else Mmt -= 0.25;			//Subtract Friction From Momentumx
				}
				
				//Animation
				if( Evt == "" )
				{
					if( Ani )
					{
						Ani	= 8;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Land( 0.25 );
				
				//Sound
				break;

			case "Crawl":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( receiver.IsKeyDownUp( EKEY_KEY_W ) ||
					receiver.IsKeyDownUp( EKEY_KEY_S ) ||
					receiver.IsKeyDownUp( EKEY_KEY_A ) ||
					receiver.IsKeyDownUp( EKEY_KEY_D ) ||
					receiver.IsKeyDownUp( EKEY_CONTROL ))
				{
					Ste	= "Crouch";
				}
				
				//Animation
				if( Evt )
				{
					if( Ani ! 7 )
					{
						Ani = 7;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Move( 2 );
				this.Collide();
				
				//Sound
				break;

			case "Jump":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( Mmt ) Mmt -= 0.25;								//Set Momentum to null
				if( SprTim <= 0 && Bmp == true ) SprTim = 1000;	//Start Spring Timer
				if( SprTim > 0 ) SprTim -= 1000 / LastFPS;		//Update Spring Timer
				if( SprTim <= 0 && Bmp == false ) SprTim = 0;		//Stop Spring Timer
				//if( Lnd == true ) Ste = "Stand";					//Only Needed for Testing
				if( Lnd == true ) Land( 0.25 )	;					//* Need to Find Deaccelleration Value
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 3 )
					{
						Ani = 3;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Glide( 4 );
				this.Collide();
				
				//Sound
				break;

			case "Flip":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( Mmt ) Mmt -= 0.25;								//* Incomplete, May Not be Nessasary
				if( SprTim <= 0 && Bmp == true ) SprTim = 1000;	//Start Spring Timer
				if( SprTim > 0 ) SprTim -= 1000 / LastFPS;		//Update Spring Timer
				if( SprTim <= 0 && Bmp == false ) SprTim = 0;	//Stop Spring Timer
				//if( Lnd == true ) Ste = "Stand";					//Only Needed for Testing
				if( Lnd == true ) Land( 0.25 );					//* Need to Find Deaccelleration Value
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 4 )
					{
						Ani = 4;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Glide( 3 );
				this.Collide();
				
				//Sound
				break;

			case "Leap":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( Mmt ) Mmt -= 0.25;				//* Incomplete, May Not be Nessasary
				if( Lnd == true ) Ste = "Stand";	//* Needed For Testing Only
				//if( Lnd == true ) Land();			//* Need to Find Deaccelleration Value
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 6 )
					{
						Ani = 6;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Glide( 3 );
				this.Collide();
				
				//Sound
				break;

			case "Spring":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( Mmt ) Mmt -= 0.25;				//* Incomplete, May Not be Nessasary
				if( Lnd == true ) Ste = "Stand";	//* Needed For Testing Only
				//if( Lnd == true ) Land();			//* Need to Find Deaccelleration Value
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 5 )
					{
						Ani = 5;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Glide( 1 );
				this.Collide();
				
				//Sound
				break;

			case "Climb":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas = Nde.getFrameNr();
						EvtTim -= 1000 / LastFPS;
					}
				}
				
				if( receiver.IsKeyDown( EKEY_KEY_W ))
				{
					this.Climb( 2.5 );
				}
				else if( receiver.IsKeyDown( EKEY_KEY_S ))
				{
					this.Climb( 3.5 );
				}
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 9 )
					{
						Ani	= 9;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				if( Vel.getY() > 0 )
				{
					Nde.setAnimationSpeed( 12 );
				}
				else if( Vel.getY() < 0 )
				{
					Nde.setAnimationSpeed( -12 );
				}
				else
				{
					Nde.setAnimationSpeed( 0 );
				}
				
				//Sound
				break;

			case "Hang":
				//Logic
				Nde.getPosition();
				//Animation
				break;

			case "Fall":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				if( Mmt ) Mmt -= 0.25;				//* Incomplete, May Not be Nessasary
				if( Lnd == true ) Ste = "Stand";	//* Need to Find Deaccelleration Value
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 10 )
					{
						Ani	= 10;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
						//*Change Ellipsoid Dimensions
					}
				}
				
				//Physics
				this.Glide( 2 );
				this.Collide();
				
				//Sound
				break;

			case "Dead":
				//Logic
				if( Evt )
				{
					//End of Event Animation
					if( Nde.getFrameNr() < AniLas && EvtTim <= 0 )
					{
						Evt		= "";
						AniLas	= 0;
						EvtTim	= 0;
					}
					//Elapse Event Animation
					else
					{
						AniLas	= Nde.getFrameNr();
						EvtTim	-= 1000 / LastFPS;
					}
				}
				
				//Animation
				if( Evt == "" )
				{
					if( Ani ! 12 )
					{
						Ani	= 12;
						Nde.setFrameLoop( AniInf[Ani][1], AniInf[Ani][2] );
					}
				}
				break;
			default:
		}
		//Obstacle
		//* Test the Position of Each Node
		vector3df	UsrPos	= Nde.GetPosition();
		
		//* Test Visible Objects
		for each( void O; VisObj )
		{
			typeid	ObjTyp	= typeid( O.Value());
			float	ObjDst	= ObjTyp.FindField( "Nde" ).GetPosition().getDistanceFrom( UsrPos );
			
			//Less Than Visual Range
			if( ObjDst < VisRng )
			{
				switch( ObjTyp.SuperType().Name())
				{
					case "entity";
						//Update
						
					case "prop";
						//Update
						
					case "backdrop";
						//Update
						
					case "collectable";
						//Update
					default;
				}
				if( ObjDst < ActRng )
				{
					//Move to Active Range
					ActObj.AddLast( O.Value());
					O.Remove();
				}
			}
			//Greater Than Visual Range
			else
			{
				//Invisible
				//Move Object to Inactive Range
				InaObj.AddLast( O.Value());
				O.Remove();
			}
		}
		
		//* Test Active Objects
		for each( TLink O; void ActObj )
		{
			typeid	ObjTyp	= typeid( O.Value());
			float	ObjDst	= ObjTyp.FindField( "Nde" ).GetPosition().getDistanceFrom( UsrPos );
			
			//Less Than Active Range
			if( ObjDst < ActRng )
			{
				switch( ObjTyp.SuperType().Name())
				{
					case "entity";
						//Update
						//Animate
						
					case "prop";
						//Update
						//Animate
						
					case "backdrop";
						//Update
						//Animate
						
					case "collectable";
						//Update
						//Animate
				default;
				}

				if( ObjDst < IntRng )
				{
					//Move to Interactive Range
					IntObj.AddLast( O.Value());
					O.Remove();
				}
			}
			//Greater Than Active Range
			else
			{
				//Move Object to Visual Range
				VisObj.AddLast( O.Value());
				O.Remove();
			}
		}
		
		//* Test Interactive Objects
		for each( TLink O; ObjLst )
		{
			typeid	ObjTyp	= typeid( O.Value());
			float	ObjDst	= ObjTyp.FindField( "Nde" ).GetPosition().getDistanceFrom( UsrPos );
			
			//Less Than Interactive Range
			if( ObjDst < IntRng )
			{
				//Interactive Object
				//* Test Object For Collision
				switch( ObjTyp.SuperType().Name())
				{
					case "entity";
						//Update
						//Animate
						//* entity Collide
						//O.Collide()
					case "prop";
						//Update
						//Animate
						//* prop Collide
						//* Test Area Trigger
					case "backdrop";
						//Update
						//Animate
						//* Backdrop Collide
						backdrop( O.Value()).Collide( UsrObj );
						break;

					case "collectable";
						//Update
						//Animate
						//* Collectable Collide
						//O.Collide()
				default;
				}
			}
			//Greater Than Interactive Range
			else
			{
				//Move Object to ActRng
				ActObj.AddLast( O.Value());
				O.Remove();
			}
		}
	}
	Move( float Spd )
	{
		//Physics
		matrix4	M1;
		matrix4	M2;
		vector3df	UsrPos	= Nde.GetPosition();						//User Position
		vector3df	CamPos	= RPGCamera.Nde.getAbsolutePosition();	//Camera Position
		vector3df	Fwd		= vector3df<s32>( 0, 0, Spd * ConSpd );		//Forward Vector
		float		CamAng	= vector2df<s32>( UsrPos.getX() - CamPos.getX(), UsrPos.getZ() - CamPos.getZ()).getAngle();
		
		//* Rotate to Terrain Surface X and Y Angle
		//* Check if Player is Landed on the Ground
		M1.setRotationDegrees( vector3df<s32>( 0, CamAng, 0 ));
		M2.setRotationDegrees( vector3df<s32>( 0, ConDir.getAngle(), 0 ));
		M1.MultEq( M2 );
		M1.transformVect( Fwd );
		Nde.SetRotation( M1.getRotationDegrees());
		Vel.setX( Fwd.getX());
		Vel.setZ( Fwd.getZ());
	}
	Glide( float Drf )
	{
		//Physics
		matrix4	M1;		//Rotation Matrix
		matrix4	M2;		//Trasformation Matrix
		vector3df	Fwd	= vector3df<s32>( 0, 0, Drf * ConSpd );	//Forward Vector
		
		//Test Rotate Forward by Control Direction
		//Fwd.rotateXZBy( Nde.GetRotation().getY() + ConDir.getAngle(), Nde.GetPosition())
		
		//Multiplay Control Direction by Momentum
		M1.setRotationDegrees( vector3df<s32>( 0, Nde.GetRotation().getY(), 0 ));
		M2.setRotationDegrees( vector3df<s32>( 0, ConDir.getAngle(), 0 ));
		M1.MultEq( M2 );
		M1.transformVect( Fwd );
		
		//Add Drift to Velocity
		Nde.SetPosition( Nde.GetPosition().Plus( Fwd ));
	}
	Land( float Dcl )
	{
		//Find Motion Velocity, Rotatate 180 Degrees, and Then Subtract Deceleration Speed
		if( vector3df<s32>( Vel.getX(), 0, Vel.getZ()).getLength())
		{
			//Find Motion Velocity
			vector3df	MotVel;								//Motion Velocity Vector
			
			MotVel.setY( vector2df<s32>( Vel.getX(), Vel.getZ()).getAngle());	//Y Angle
			
			//Rotate 180 Degrees
			matrix4	M;
			vector3df	Fwd	= vector3df<s32>( 0, 0, Dcl );		//Rate of Deceleration
			
			M.setRotationDegrees( MotVel.Minus( vector3df<s32>( 0, - 90, 0 )));
			M.rotateVect( Fwd );
			
			//Subtract Deceleration Vector
			Vel.MinusEq( vector3df<s32>( Fwd.getX(), 0, Fwd.getZ()));
			MotVelTst = vector3df<s32>( Fwd.getX(), 0, Fwd.getZ()).Mult( 100 );	//* Test Variable
			
			//Check if Vel is in Resting Range and Set to Zero
			if( vector2df<s32>( Vel.getX(), Vel.getZ()).getLength() <= 0.75 ) Vel = vector3df<s32>( 0, Vel.getY(), 0 );
		}
	}

	Collide( list Body )
	{
		//Gravity
		if( Vel.getY() > -6 )
		{
			Vel.MinusEq( Map.Grv );
		}
		else if( Ste ! "Fall" && Lnd == false )
		{
			Ste = "Fall";
		}

		//Collision Response
		int	Fll;	//Needed as Place Holder
		
		LasPos.setEq( Nde.GetPosition());
		Nde.SetPosition( Col.getCollisionResultPosition( Slc, Nde.GetPosition(), Elp, Vel, Tri, VarPtr( Fll )));
		Nde.updateAbsolutePosition();
		
		//Land
		vector3df	UsrPos	= Nde.GetPosition();	//Current Node Position
		
		if( vector3df<s32>( 0, LasPos.getY() + Vel.getY(), 0 ).getDistanceFrom( vector3df<s32>( 0, UsrPos.getY(), 0 )) > 0.20 &&
			LasPos.getY() > UsrPos.getY())
		{
			FallTest	= "True";	//* Test Variable
			Lnd			= true;
			Evt			= "Fell";	//* Set Land Event For Hurt Function
			Vel.setY( 0 );
		}
		
		//Knock
		else if( vector3df<s32>( 0, LasPos.getY() + Vel.getY(), 0 ).getDistanceFrom( vector3df<s32>( 0, UsrPos.getY(), 0 )) > 0.20 &&
			LasPos.getY() < UsrPos.getY())
		{
			Lnd	= false;
			Vel.setY( 0 );
		}
		else
		{
			FallTest	= "False";	//* Test Variable
			Lnd			= false;
		}
		
		/*
		Object Collision * Need to Test Mesh Collision && Object Type
		Local ObjNde:IAnimatedMeshSceneNode[]			//Animated SceneNodes
		Local UsrBox:AABbox3df = Nde.getBoundingBox()	//User Bounding Box
		
		ObjArr = null
		smgr.getSceneNodesFromType( ESNT_ANIMATED_MESH, ObjNde )
		
		for Local Obj:ISceneNode = EachIn ObjNde
			
			//Check if Object is Within Average Object Collision Radius
			if( Obj.getPosition().getDistanceFrom( UsrPos ) < 200
				
				Test Bounding Box Collision
				if( UsrBox.intersectsWithBox( Obj.getBoundingBox())
					
					Add Obj to Object Array
					AddLast ObjArr, Obj
				}
			}
		}
		
		if( Lnd == true && LndCnt == false
			cout << "Landed" << endl;
			LndCnt = true
		else if( Lnd == false && LndCnt == true
			cout << "Falling" << endl;
			LndCnt = false
		}
		
		if( lastpos Y plus velocity Y ! current pos Y Then Land
		if( Lastpos Y plus Velocity Y - Current Pos Y Get Distance > 6 Then Fell
		
		Local VelLin:line3df = line3df( NodPos, vector3df<s32>( NodPos.getX(), NodPos.Plus( Vel ).getY() + ( Epd.getY() / 2 ), NodPos.getZ()))
		Local Isc:vector3df = vector3df
		
		Line.setLineFromVects( Cam.Node.getAbsolutePosition(), ..
			Line.getStart().Plus(( Cam.Node.getTarget().Minus( Line.getStart())).normalize().Mult( 1000.0 )))
		
		if( ( Col.getCollisionPoint( ..
			VelLin, Slc, Isc, Tri ))
			
			if( user.Ste == "Jump" Then user.Ste = "Stand"
			Vel.setY( 0 )
			driver.SetTransform( ETS_WORLD, matrix4.create())
			driver.draw3DTriangle( Tri, _SCOLOR( 255, 255, 0, 0 ))
		Endif
		if( lastpos Y plus velocity Y ! current pos Y Then fell
		if( LstPos.Plus( Vel ).getY() ! NodPos.getY()
			if( user.Ste == "Jump" Then user.Ste = "Stand"
			Vel.setY( 0 )
		}
		*/
		
		//* Bumped, May need to use as function withing states.
		//Difference between: Distance between Last Position plus Velocity, Current Position, and Bump Sensitivity
		//* May have mistyped NdePos and Changed to UsrPos
		if( vector3df<s32>( LasPos.getX() + Vel.getX(), 0, LasPos.getZ() + Vel.getZ()).getDistanceFrom( vector3df<s32>( UsrPos.getX(), 0, UsrPos.getZ())) > 2 )
		{
			//Bumped
			BumpTest	= "True";	//* Test Variable
			Bmp			= true;
			if( Evt == "" ) Evt = "Bumped";
		}
		else
		{
			//Not Bumped
			BumpTest	= "False";	//* Test Variable
			Bmp			= false;
		}
		
		//* Incomplete //Ge t Terrain Slope
		//* Check Land and Bump Flag Then Check Terrain Slope
		if( Lnd == false )
		{
			vector3df	TriNrm	= Tri.getNormal().normalize();						//Angle Standing on Triangle
			float		SlpAng	= vector2df<s32>(											//Surface Slope Angle
				-vector2df<s32>( 0, TriNrm.getY()).getLength(),							//XZ Distance
				vector2df<s32>( TriNrm.getX(), TriNrm.getZ()).getLength()).getAngle();	//Y Height
			
			if( SlpAng > 180 && SlpAng < 225 )
			{
				vector3df		LndPos; 
				triangle3df	LndTri;	//Needed as Place Holder
				line3df		FalLin	= line3df( UsrPos, UsrPos.Minus( vector3df<s32>( 0, Elp.getY() + 10, 0 )))	//User Collsion Line
				
				//* Need to Translate FalLin to Maps World Space
				Col.getCollisionPoint( FalLin, Map.Slc, LndPos, LndTri );	//Get Land Position
				LndPosTst	= LndPos;	//* Test Variable
				Nde.SetPosition( LndPos.Plus( vector3df<s32>( 0, Elp.getY() + 0.5, 0 )));	//Set User To Ground Level
				//* Might Try Setting the Y Velocity in the Angle of the Slope
			}
			SrfAngTst	= SlpAng;	//* Test Variable
			//Nde.SetRotation()	//Set Node Rotation to Node Angle Minus Tri Normal YX and YZ Angles
		}
		
		/*
		BmpLst vector3df<s32>( LstPos.getX() + Vel.getX(), 0, LstPos.getZ() + Vel.getZ()) //Estimated Distance
		BmpCur vector3df<s32>( NdePos.getX(), 0, NdePos.getZ()) //Current Distance
		
		if( vector3df<s32>( LastPos.getX(), 0, LastPos.getZ()).Plus( vector3df<s32>( Velocity.getX(), 0, Velocity.getZ())).getDistanceFrom( vector3df<s32>( Node.getPosition().getX(), 0, Node.getPosition().getZ())) > 0
			if( State == "Jump" || State == "Spring"
				Usr.Jump()
			else if( State == "Flip" || State == "Leap" || State == "Run"
				Event = "Bump"
				Usr.Hurt()
			else
				Velocity.setX( 0 )
				Velocity.setZ( 0 )
			}
		}
		*/
	}
	Climb( float Spd )
	{
		//Check Active Ladder
		for each( list ActObj; ladder ObjTyp )
		{
			if( typeid( ObjTyp ).name() == "ladder" )
			{
				ladder		ActLad	= ladder( ObjTyp );	//Active Ladder
				vector3df	UsrRot	= Nde.GetRotation();	//User Node Rotation
				
				//Physics
				//*End of Ladder
				//*Next Ladder
				
				//Climb Ladder
				//*Set User Rotation To Face Ladder
				Nde.SetRotation( vector3df<s32>( UsrRot.getX(), 0, UsrRot.getZ()));
				
				//Set Velocity to Climb Direction and Speed
				Vel.Set( 0, ConSpd * Spd * ConDir.getY(), 0 );
				
				//Set Position to Ladder Center
				//LadRad Rotated by Ladder Dir Around Obj Center
				Nde.SetPosition( vector3df<s32>( ActLad.Nde.GetPosition().getX(), Nde.GetPosition().getY(), ActLad.Nde.GetPosition().getZ() - ActLad.Rad ));
			}
		}
	}
	Hang()
	{
		//Set for hanging from overhangs and ceilings
		Vectr3df	UsrRot	= Nde.GetRotation();	//User Node Rotation
		
		//*Set User Rotation Parallel to Support
		Nde.SetRotation( vector3df<s32>( UsrRot.getX(), 0, UsrRot.getZ()));
		
		//*Set Velocity to Hang Direction and Speed
		Vel.Set( 0, ConDir.getY(), 0 );
		
		//*Set Position to Support Center
	}
	Jump()
	{
		//Jump
		if( Lnd == true &&
			Ste == "Stand" ||
			Ste == "Walk" ||
			Ste == "Crouch" ||
			Ste == "Crawl" )
		{
			//Physics
			Vel.PlusEq( vector3df<s32>( 0, 7, 0 ))	;	//* Incomplete, Could use an Angle to calculate the Velocity Vector
			
			//Logic
			Ste	= "Jump";
		}

		//Flip
		else if( Ste == "Jump" )
		{
			//Physics
			Vel.PlusEq( vector3df<s32>( 0, 5, 0 ));	//* Incomplete, Could use an Angle to calculate the Velocity Vector
			
			//Logic
			Ste	= "Flip";
		}

		//Leap
		else if( Lnd == false && Ste == "Run" )
		{
			//Physics
			matrix4	M;
			vector3df	Frc	= vector3df<s32>( 0, 7, 5 );
			
			M.setRotationDegrees( Nde.GetRotation());	//* Incomplete, Could use an Angle to calculate the Velocity Vector
			M.transformVect( Frc );
			user.Vel.PlusEq( Frc );
			
			//Logic
			Ste	= "Leap";
		}

		//Spring
		else if( Ste == "Climb" ||
			SprTim > 0 &&
			Ste == "Jump" )
		{
			//Physics
			matrix4	M;
			vector3df	Frc	= vector3df<s32>( 0, 5, 7 );
			
			Nde.SetRotation( Nde.GetRotation().Minus( vector3df<s32>( 180, 0, 0 )));
			M.setRotationDegrees( Nde.GetRotation());	//* Incomplete, Could use an Angle to calculate the Velocity Vector
			M.transformVect( Frc );
			Vel.setEq( Frc );
			
			//Logic
			Ste		= "Spring";
			SprTim	= 0;
		}

		//Lift
		else if( Ste == "Hang" ||
			Ste == "Climb" )
		{
			//Physics
			//Logic
		}
	}
	Use( void Obj )
	{
		//Use
		for each( void Obj: void ObjLst )
		{
			switch( typeid( Obj ).name())
			{
				//* Check Item Pickup
				case "collectable";
					
					//* Collect Closest Collectable
					Evt	= "PickUp";
					break;

				//* Check BackDrop Interaction
				case "ladder";
					ladder	SlcLad	= ladder( Obj );	//selected Ladder
					
					if( Ste ! "Climb" && Vel.getLength() < 1.5 )
					{
						//Check if Player is Facing a Ladder
						vector3df	UsrPos	= Nde.GetPosition();			//User Position
						vector3df	UsrRot	= Nde.GetRotation();			//User Rotation
						vector3df	LdrPos	= SlcLad.Nde.GetPosition();	//Ladder Position
						float		LdrAng	= vector2df<s32>(	//Ladder Angle
							LdrPos.getX() - UsrPos.getX(), LdrPos.getZ() - UsrPos.getZ()).getAngle() - UsrRot.getY();
						
						if( LdrAng < -45 && LdrAng > 45 )
						{
							//* Step On Ladder
							Ste	= "Climb";
							
							//* Add Obj to ActObj List
							ObjArr[3][1];
							ObjArr.AddLast( SlcLad );
						}
					}
					//Check if Player is Climbing a Ladder
					else if( Ste == "Climb" )
					{
						//* Drop Off Ladder
					}
					break;

				case "trigger";
					//* Check if Player is Facing Trigger
					trigger	SlcTrg	= trigger( Obj );				//selected Trigger
					vector3df	UsrPos	= Nde.GetPosition();			//User Position
					vector3df	UsrRot	= Nde.GetRotation();			//User Rotation
					vector3df	TrgPos	= SlcTrg.Nde.GetPosition();	//Ladder Position
					float		TrgAng	= vector2df<s32>				//Ladder Angle
						( TrgPos.getX() - UsrPos.getX(), TrgPos.getZ() - UsrPos.getZ()).getAngle() - UsrRot.getY();
					
					if( TrgAng < -45 && TrgAng > 45 )
					{
						//* Add Obj to ActObj List
						ActObj.AddLast( SlcTrg );
						
						//* Check if Trigger is Inactive
						//* Check Keys
							//* Check if Delay has Expired
							//* Activate Trigger
							SlcTrg.Activate();
							
						//* Check if Trigger is Active
						//* Check if Timer has Stopped
							//Deactivate Trigger
							SlcTrg.Deactivate();
					}
					break;

				//* Check entity Interaction
				case "enemy";
					
				//* Check Clan Interation
				case "friendly";
					
			default;
			}
		}
	}
	ActionPri()
	{
		//*Check if Melee
			//Punch *Stand/Walk/Jump and Action
				//Right or Left Jab
				//Opposite Arm Hook
				//Uppercut
				
			//UpperCut *Crouch/Crawl and Action
			//Dash *Run and Action
			//Stomp *Should Be in Crouch *Jump and Crouch
			
		//*Check if Weapon/Item
			//Swing *Stand/Walk and Action
			//Thrust *Run and Action
			//Spin *Crouch and Action
			
		//*Check if Ranged Weapon
		//Shoot *Stand/Walk/Jump/Crouch and Action
		if( Amm[3] == 0 && Amm[1] > 0 )
		{
			//Ranged
			if( WpnInf[Eqp[0]][6] )
			{
				projectile.Use( int( WpnInf[Eqp[0]][6] ));
			}
		}
	}
	ActionSec()
	{
		//*Check if Melee
			//Kick *Stand/Walk and Action
			//Jump Kick *Jump/Leap and Action
			//Slide *Run and Kick
			
		//Check if Item
		if( Amm[3] == 1 && Amm[2] > 0 )
		{
			//Ranged
			if( EqpInf[Eqp[1]][6] )
			{
				projectile.Use( int( EqpInf[Eqp[1]][6] ));
			}
		}
	}
	Hurt( int Dmg, vector2df Frc )
	{
		switch( Evt )
		{
		case "Impact";
			//Logic
			Hth	-= Dmg;
			
			//Animation
			//* Flash Player Visibility
			
			//Physical
			Vel.PlusEq( vector3df<s32>( Frc.getX(), 0, Frc.getY()));
			Mmt	= 0;
			
			//Sound
			//* Player Damage Magnitude
				//Grunt
				//Shout
			break;

		case "Bumped";
			//Physical
			Mmt	= 0;
			
			//Animation
			//Sound
			//* Player Bump Magnitude
				//Grunt
			break;

		case "Fell";
			//Physical
			Mmt	= 0;
			
			//Animation
			//Sound
			break;

		default;
		}
	}
	Die()
	{
		Ste		= "Dead";	//Dead User State
		GmeSte	= "Dead";	//Dead Game State
	}
private:
	list						Count;				//List of Users
	ISceneNode					NdeArr[];			//Object SceneNode Array

	Initialize( vector3df Pos, vector2df Rot, IAnimatedMesh Msh, string Nam, string Skl, string Wpn, string Itm )
	{
		//Client
		if( ! this ) this.UsrObj = new user;
		this.Msh		= Msh;
		this.Ste		= "Stand";
		this.Nde		= smgr.addAnimatedMeshSceneNode( Msh, null, null, Pos, Rot, Scl, true );
		this.Nde.SetPosition( Pos );
		this.Elp		= vector3df<s32>( 20, 40, 20 );
		this.Nde.setMaterialTexture( 0, this.Skn );
		this.Nde.setMaterialFlag( EMF_LIGHTING, false );
		this.Nde.setDebugDataVisible( Profile.debug );
		this.Nde.setAnimationSpeed( 0 );
		if( Profile.input == "joystick" )
			this.Ipt->getJoystick()->rumble( 10000, 0x8000 );

		//Server
		//Register in Server Lobby
		return this;
	}
	Remove( list Usr )
	{
		for each( user U; list Usr )
		{
			U.Nde.Remove();
			U.Msh.Remove();
			
			user::Cnt::erase( U );
			return U;
		}
	}
};

class RPGCamera
{
//eMotion Camera
public:
	ISceneNode			Usr;	//Active Player
	ICameraSceneNode	Nde;	//Camera Node
	vector3df		 	Epd;	//Camera Ellipsoid
	stringw			Ste;	//Camera State
	line3df			Pth[];	//Path Array
	vector3df			DltRot;	//Delta Rotation
	vector3df			DltPos;	//Delta Position
	vector3df			DltOfs;	//Delta Target Offset
	
	Update()
	{
		//Calculate Camera Position From Delta Position
		vector3df	UsrPos		= Usr.getPosition();			//User Position
		vector3df	CamPos		= Nde.getPosition();				//Camera Position
		float		CamDstHrz	=									//Camera Horizontal Distance
			vector3df<s32>( UsrPos.getX(), 0, UsrPos.getZ()).getDistanceFrom( vector3df<s32>( CamPos.getX(), 0, CamPos.getZ()));
		float		CamDstVrt	= CamPos.getY() - UsrPos.getY();	//Camera Vertical Distance
		float		FwdAng		=									//Not Sure //Forward Facing Angle of Camera
			vector2df<s32>( CamPos.getX() - UsrPos.getX(), CamPos.getZ() - UsrPos.getZ()).getAngle();
		
		if( CamDstHrz > 100 )
		{
			matrix4	M;
			vector3df	Fwd	= vector3df<s32>( 0, 0, CamDstHrz - 100 );
			
			M.setRotationDegrees( vector3df<s32>( 0, FwdAng - 90, 0 ));
			M.rotateVect( Fwd );
			Nde.SetPosition( CamPos.Plus( Fwd ));
		}
		else if( CamDstHrz < 50 )
		{
			matrix4	M;
			vector3df	Fwd	= vector3df<s32>( 0, 0, - CamDstHrz );
			
			M.setRotationDegrees( vector3df<s32>( 0, FwdAng - 90, 0 ));
			M.rotateVect( Fwd );
			Nde.SetPosition( CamPos.Plus( Fwd ));
		}
		if( CamDstVrt > 110 )
		{
			Nde.SetPosition( CamPos.Plus( vector3df<s32>( 0, - 2, 0 )));
		}
		else if( CamDstVrt < 90 )
		{
			Nde.SetPosition( CamPos.Plus( vector3df<s32>( 0, 2, 0 )));
		}
		
		//Calculate Camera Rotation From Delta Rotation
		Nde.setTarget( UsrPos );
		
		//Camera State
		switch( Ste );
		{
		//CutScene
		case "CutScene";
			break;

		//Orbit "Debug"
		case "Orbit";
			
			//Target User
			vector3df	UsrPos	= UsrNde.getPosition();
			
			//Maya Rotate
				//Get Mouse X Difference and Add to X Transformation
				//Get Mouse Y Defference and Add to Y Transformation
			break;

		//FlyBy "Debug"
		case "FlyBy";
			
			//FPS Movement
			//get sPline code.   
			break;

		//Idle
		case "Idle";
			
			//Find Current Position of User
			vector3df	UsrPos	= UsrNde.getPosition();
			
			//Hover Behind User
			vector2df	UsrNrm	= UsrNde.GetRotation();
			break;

		//Chase
		case "Chase";
			
			//Increase Field of View To Max 90
			if( Nde.getFOV() < 90 )
			{
				Nde.setFOV( Nde.getFOV() + 1 );
			}
			
			//Follow Position of User
			vector3df	UsrPos	= UsrNde.getPosition();
			vector2df	UsrNrm	= UsrNde.GetRotation();
			break;

		//Climb
		case "Climb";
			
			//Follow Player Height
			vector3df	UsrPos	= UsrNde.getPosition();
			break;

		//Crouch
		case "Crouch";
			
			//Lower Camera Height To Above Ground Level
			vector3df	UsrPos	= UsrNde.getPosition();
			break;

		//Hold
		case "Hold";
			
			//Pause Movement
			DltPos	= UsrNde.getPosition();
			break;

		//Attack
		case "Attack";
			
			//Frame User and Target/s
			break;

		//Spectate
		case "Spectate";
			
			//Maya Rotate
			//Frame User and Friends
			break;

		//Dead
		case "Dead";
			
			//Increase Camera Distance
			//Decrease Field Of View
			break;

		default;
		}
	}
	Collide( triangle3df Fac )
	{
		//Return Collision Face
		
		return Fac;
	}

private:
	list				Cnt;	//List of RPGCameras

	Initialize( vector3df Pos, ISceneNode UsrNde, stringw Ste, int Far, line3df Pth[] )
	{
		if( ! this ) Usr = UsrNde;
		this.Lok	= Usr.getPosition();
		Ste	= Ste;
		Nde	= smgr.addCameraSceneNode( null, Pos, Lok, null );
		Epd	= vector3df( 7.2, 7.2, 7.2 );

		return;
	}
	Remove( list Cam )
	{
		for each( RPGCamera C; RPGCamera Cam )
		{
			C.Nde->Remove();
			C.Usr			delete;
			C.Ste		=	null;
			C.Pth			delete;
			C.DltRot		delete;
			C.DltOfs		delete;
			C.DltPos		delete;
		}

		return C;
	}
};

class entity
{
protected:
	string						Nam;		//entity Name
	IAnimatedMesh				Msh;		//entity Mesh
	IAnimatedMeshSceneNode	Nde;		//entity Scenenode
	actor						Ani;		//entity Animator
	vector3df					Epd;		//entity Collision Ellipsoid
	vector3df					Vel;		//entity Velocity
	vector3df					Dsp;		//Displacement from Last Position
	vector3df					LstPos;		//Last Position
	string						Ste;		//Primary entity State
	string						Evt;		//Secondary entity State
	float						Hth;		//entity Health
	string						Itm[][];	//entity Item Name, selected Item Slot
	string						Wpn[][];	//entity Weapon Name, selected Weapon Slot
	int							Ani[][];	//Animation: First Frame, Last Frame
	triangle3df				Tri;		//Triangle Output from Collision
	int							Fll;		//entity is Falling
	
	Update()
	{
		//Mode
		switch( Mde )
		{
		case "Ignore";
		case "Follow";
			//Target Nearest Friend
			entity	Trg;		//Nearest Target
			float	LstDst;		//Last Distance
			
			for each( entity Ent; entity entity.Cnt())
			{
				if( Ent.Nde.getPosition().getDistanceFrom( this.Nde.getPosition()) < LstDst )
				{
					Trg			= Ent;
					this.Pth	= null;
					this.Pth[0].setLineFromLineVects( this.Nde.getPosition(), Trg );
					LstDst		= Ent.Nde.getPosition().getDistanceFrom( this.Nde.getPosition());
				}
			}
			
			matrix4f	M;
			
			//Find shortest path to Target
			vector3df	Nrm = entity( Trg ).Nde.getPosition().Minus( this.Nde.getPosition()).Normalize().MultVect( vector3df<s32>( LstDst, 0, LstDst ));
			
			if( Map.Slc.getTrianglesOnLine( Pth[Pth.Length - 1] )
			{
				Pth[Pth.Length]( Pth[Pth.Length - 1].getEnd(), Col.getCollisionResultPosition( Map.Slc(), this.Nde.getPosition(), Epd, Nrm, this.Tri(), null, 0, vector3df<s32>( 0, Nrm.getLength(), 0 )));
			}
			
			this.Nde.getPosition().getDistanceFrom( this.Pth[0].getEnd());
			
			//Find Cost of Path
			for( int N; 1 to 8 )
			{
				if( Map.Slc.getTrianglesOnLine( line3df()( this.Nde.getPosition(), Nrm()), M )
				{
					//Set Path
					Pth[Pth.Length - 1] = line3df( Nrm, Trg );
					break;
				}
				else
				{
					Nrm.rotateXZBy( 45 );
				}
			}
			break;
				
		case "Lead";
			break;
		default;
		}

		//State
		switch( Ste )
		{
			case "Stand";
				//Logic
				//Animation
				//Sound
				//Server
				break;
			case "Walk";
				break;
			case "Run";
				break;
			case "Crawl";
				break;
			case "Fall";
				break;
			case "Jump";
				break;
			case "Dead";
				break;
		default;
		}

		//Event
		switch( Evt )
		{
			case "Appear";
				break;
			case "Attack";
				break;
			case "Block";
				break;
			case "Hurt";
				break;
			case "Die";
				break;
			case "Disappear";
				break;
		default;
		}
	}
	Move( float Spd )
	{
	}
	Jump( float Str)
	{
	}
	Glide( float Spd )
	Land()
	{

	}
	Collide( void Body )
	{
	}
	Climb( float Spd )
	Use( void Body )
	{
	}
	ActionPri()
	{
	}
	ActionSec()
	{
	}
	Hurt( float Dmg )
	Die()
	Remove()
	{
		this.Nde.Remove();
		this.Msh.Remove();

		entity::Cnt::erase( this );
		return this;
	}
private:
	list				Cnt;	//List of Entities
	ITriangleselector	Slc;	//Triangle selector
	Create( string Nam, IAnimatedMesh Msh, ISceneNode Nde, vector3df Epd, string Ste, string Evt, float Hth, string Itm[][], string Wpn[][] )
	{
		//Client
		entity	E	= new entity;

		entity::Cnt::push_back( E );

		//Server
		
	}
};

class friendly : public entity
{
public:
	string	Mde;	//A.I. Mode
	string	PthNde;	//Path Node
	list	OpnPth;	//Path Open Nodes
	list	ClsPth;	//Path Closed Nodes
	list	CstPth;	//Path Node Cost
	
	Update()
	{
		//Wave
		//for( int Millisecond; Start to End; Timing ) Event;
		//if( trigger ) Event;

		//Mode
		switch( Mde )
		{
		case "Ignore";
			break;
		case "Follow";
			//Target Nearest Friend
			entity	Trg;		//Nearest Target
			float	LstDst;		//Last Distance
			
			for each( entity Ent; entity entity.Cnt())
			{
				if( Ent.Nde.getPosition().getDistanceFrom( this.Nde.getPosition()) < LstDst )
				{
					Trg			= Ent;
					this.Pth	= null;
					this.Pth[0].setLineFromLineVects( this.Nde.getPosition(), Trg );
					LstDst		= Ent.Nde.getPosition().getDistanceFrom( this.Nde.getPosition());
				}
			}
			
			matrix4f	M;
			
			//Find shortest path to Target
			vector3df	Nrm = entity( Trg ).Nde.getPosition().Minus( this.Nde.getPosition()).Normalize().MultVect( vector3df<s32>( LstDst, 0, LstDst ));
			
			if( Map.Slc.getTrianglesOnLine( Pth[Pth.Length - 1] )
			{
				Pth[Pth.Length]( Pth[Pth.Length - 1].getEnd(), Col.getCollisionResultPosition( Map.Slc(), this.Nde.getPosition(), Epd, Nrm, this.Tri(), null, 0, vector3df<s32>( 0, Nrm.getLength(), 0 )));
			}
			
			this.Nde.getPosition().getDistanceFrom( this.Pth[0].getEnd());
			
			//Find Cost of Path
			for( int N; 1 to 8 )
			{
				if( Map.Slc.getTrianglesOnLine( line3df()( this.Nde.getPosition(), Nrm()), M )
				{
					//Set Path
					Pth[Pth.Length - 1] = line3df( Nrm, Trg );
					break;
				}
				else
				{
					Nrm.rotateXZBy( 45 );
				}
			}
			break;
				
		case "Lead";
			break;
		default;
		}

		//State
		switch( Ste )
		{
			case "Stand";
				break;
			case "Walk";
				break;
			case "Run";
				break;
			case "Crawl";
				break;
			case "Fall";
				break;
			case "Jump";
				break;
			case "Dead";
				break;
		default;
		}

		//Event
		switch( Evt )
		{
			case "Appear";
				break;
			case "Attack";
				break;
			case "Block";
				break;
			case "Hurt";
				break;
			case "Die";
				break;
			case "Disappear";
				break;
		default;
		}
	}
	Move()
	{
	}
	Jump()
	{
	}
	Glide( float spd )
	Land()
	Collide( void Body )
	{
	}
	Use( void Body )
	{
	}
	ActionPri()
	{
	}
	ActionSec()
	{
	}
	Hurt()
	Die()
	Remove()
	{
		this.Nde.Remove();
		this.Msh.Remove();

		entity::Cnt::erase( this );
		return this;
	}
private:
	list	Cnt;	//List of friends

	Create( string Nam, IAnimatedMesh Msh, ISceneNode Nde, vector3df Epd, string Ste, string Evt, float Hth, string Itm[][], string Wpn[][], string Mde, string PthNde )
	{
		//Client
		friendly	F	= new friendly;
		
		friendly::Cnt::push_back( F );

		//Server
	}
};

class enemy : public entity
{
public:
	string	Mde;	//A.I. Mode
	string	PthNde;	//Path Node
	list	OpnPth;	//Path Open Nodes
	list	ClsPth;	//Path Closed Nodes
	list	CstPth;	//Path Node Cost

	Update()
	{
	}

	Move()
	{
	}
	Jump()
	{
	}
	Glide( float spd )
	Land()
	Collide( void Body )
	{
	}
	Use( void Body )
	{
	}
	ActionPri()
	{
	}
	ActionSec()
	{
	}
	Hurt( float Dmg ){}
	Die(){}
	Remove()
	{
		this.Nde.Remove();
		this.Msh.Remove();

		entity::Cnt::erase( this );
		return this;
	}
private:
	Create( string Nam, IAnimatedMesh Msh, ISceneNode Nde, vector3df Epd, string Ste, string Evt, float Hth, string Itm[][], string Wpn[][] )
	{
	}
};

class backdrop
{
protected:
	IAnimatedMeshSceneNode	Nde;		//BackDrop Node
	string						Nam;		//Name of BackDrop
	float						Hzd;		//Damage Amount to User
	int							Clp;		//Object Clipping
	float						Swy;		//Bending Percentage		
	float						Hth;		//Health Percentage of BackDrop
	string						Ste;		//State of BackDrop
	actor						Act;		//Actor 
	int							Ani[][]	=	//Animation Table
		// Appr| Dsap|  Act| Stat| Coll|   
		{{   -1,    3,    5,    7,    9},	//Beggining
		{     2,    4,    6,    8,   10},	//Ending
		{     0,    0,    0,    0,    0}};	//Loop
	
	Update()
	{
	}
	Collide( void Body )
	{
		string	BTyp	= typeid( Body ).name();
		
		//* Apply User Data
		if( BTyp == "user" )
		{
			//* Damage
			if( Hzd || Clp )
			{
				if( Clp )
				{
					//Bump
					this.Hurt( Hzd, vector2df<s32>( 0, -0.16 * Hzd ).rotateBy( this.Nde.GetRotation().getY(), null ));
					list	Col	= Col.push_back( this.Ani[0][5] );
					Col.push_back( this.Nde.Current_Frame );
					this.Act.Pan( Col, user( Body ).Nde.getPosition().getDistanceFrom( this.Nde.getPosition()));
				}
				else
				{
					//Trip
					this.Hurt( Hzd, vector2df<s32>( 0, 0.16 * Hzd ).rotateBy( this.Nde.GetRotation().getY(), null ));
					list	Col	= Col.push_back( this.Ani[0][5] );
					Col.push_back( this.Nde.Current_Frame );
					this.Act.Pan( Col, user( Body ).Nde.getPosition().getDistanceFrom( this.Nde.getPosition()));
				}
			}
		}

		//* Apply entity Data
		else if( typeid( Body ).BTyp == "entity" )
		{

		}
		//* Apply Body Data
		else if( BTyp == "projectile" )
		{
			//* Damage
			if( Clp ) projectile( Body ).Destroy();
			{
				//* Hurt
				//* Subtract Health From Backdrop
			}
		}
		//* Apply Backdrop Data
			//* Damage
	}
	Destroy()
	{
	}
	Remove()
	{
		Nde.remove();
		Cnt.Remove( this );
	}
private:
	backdrop			Cnt;		//List of Backdrops
	ITriangleselector	Slc;		//Triangle selector

	Create( ISceneNode BNde, string BNam, string BAni, float BHzd, int BClp, float BHth, string BSte )
	{
		backdrop	B	= new backdrop;
		
		B.Nde	= BNde;
		B.Nam	= BNam;
		B.Ani	= BAni;
		B.Hzd	= BHzd;
		B.Clp	= BClp;
		B.Hth	= BHth;
		B.Ste	= BSte;
		
		backdrop.Cnt::push_back( B );
		return B;
	}
};

class water : public backdrop
{
public:
	ITexture	Tex;		//Water Texture
	ITexture	Sps;		//Spash Texture
	vector2df	Cur;		//Velocity of Water Current
	
	Update()
	{
		Backdrop.Update();
		switch( Ste )
		{
			case "Active";
				//Logic
				//Sound
				break;
			case "Still";
				//Logic
				//Sound
				break;
		default;
		}
	}
	Collide( void Body )
	{
		Bbb.Collide( void Body );
	} 
	Flow()
	{
	}
	Calm()
	{	
	}
	Remove()
	{
		this.Nde.remove();
		this.Cnt::erase( this );
	}
private:
	list	Cnt;		//List of Waters

	Create( ISceneNode WNde, string WNam, string WAni, float WHzd, int WClp, float WHth, string WSte, string WTex, vector2df WCur )
	{
		water W	= new water;

		//*incomplete
		RealisticWaterSceneNode* realwater	= new RealisticWaterSceneNode( dev, 1228, 1640, driver->getTexture( "./waterbump.png" ), dev->getTimer());
		
		realwater->setPosition( vector3df( 154, -360, 603 ));
		realwater->setWaterColor( SColor( 0.1f, 0.1f, 0.6f, 1.0f ));
		realwater->setWindForce( 10.0f );
		realwater->setSplitScreen( true );
		//*incomplete

		W.Nde	= WNde;
		W.Nam	= WNam;
		W.Ani	= WAni;
		W.Hzd	= WHzd;
		W.Clp	= WClp;
		W.Hth	= WHth;
		W.Ste	= WSte;
		W.Tex	= WTex;
		W.Cur	= WCur;
		
		Cnt::push_back( W );
		//ListAddLast( Cnt, W );
		//ListAddLast( WtrCnt, W );
		return W;
	}
};

class wind : public backdrop
{
public:
	vector3df	Vel;		//Velocity of Wind
	
	Update()
	{
		Backdrop.Update();
		switch( Ste )
		{
			case "Blowing";
				//Logic
				//Sound
				
			case "Calm";
				//Logic
				//Sound
		default;
		}
	}
	Collide( void Body )
	{
		Backdrop.Collide( void Body );
	}
	Blow()
	{	
	}
	Calm()
	{	
	}
	Remove()
	{
		Super( this ).Remove();
		WndCnt.Remove( this );
	}

private:
	list	Cnt;		//List of Winds
	
	Create( ISceneNode WNde, string WNam, string WAni, float WHzd, int WClp, float WHth, string WSte, vector3df WVel )
	{
		Wind	W	= new Wind;
		
		W.Nde	= WNde;
		W.Nam	= WNam;
		W.Ani	= WAni;
		W.Hzd	= WHzd;
		W.Clp	= WClp;
		W.Hth	= WHth;
		W.Ste	= WSte;
		W.Vel	= WVel;
		
		ListAddLast( Cnt, W );
		ListAddLast( WntCnt, W );
		return W;
	}
};

class ladder : public backdrop
{
public:
	vector3df	Dir;	//Direction of Ladder
	float		Rad;	//Ladder Climbing Face Radius
	
	Update()
	{
		Super.Update();
	}
	Remove()
	{
		Super.Remove();
		LdrCnt.Remove( this );
	}
private:
	list	Cnt;	//List of Ladders
	
	Create( ISceneNode LNde, string LNam, string LAni, float LHzd, int LClp, float LHth, string LSte, vector3df LDir, float LRad )
	{
		ladder	L	= new ladder;
		
		L.Nde	= LNde;
		L.Nam	= LNam;
		L.Ani	= LAni;
		L.Hzd	= LHzd;
		L.Clp	= LClp;
		L.Hth	= LHth;
		L.Ste	= LSte;
		L.Dir	= LDir;
		L.Rad	= LRad;
		
		ListAddLast( Cnt, L );
		ListAddLast( LdrCnt, L );
		return L;
	}
};

class prop
{
protected:
	IAnimatedMeshSceneNode	Nde;		//prop Node
	string						Nam;		//Name of prop
	string						Ste;		//State of prop
	vector3df					Vel;		//Velocity of prop
	int							Ani[][] =	//prop Animation Table 
		// Appr| Dspr| Actv| Stat| Coll|
		{{   -1,   -1,   -1,   -1,   -1},
		{    -1,   -1,   -1,   -1,   -1}}
	
	Update()
	{
		
		//Update Velocity
		Nde.setPosition( Nde.getposition().Plus( Vel ));
	}
	Create( IAnimatedMeshSceneNode PNde, string PNam, string PSte, int PAni[][], vector3df PVel )
	{
			prop	P	= new prop;
			
			P.Nde	= PNde;
			P.Nam	= PNam;
			P.Ste	= PSte;
			P.Ani	= PAni;
			P.Vel	= PVel;
			
			prop.Cnt::push_back( P );
			return P;
	}
	
private:
	prop				Count;	//List of props
	ITriangleselector	Slc;	//Triangle selector

	Remove()
	{
		Nde.remove();
		Cnt.Remove( this );
	}
};

class door : public prop
{
public:
	string		Swt;		//Switch Type Trip, Toggle, And, and Or
	string		Pat[];		//Current Switch, Switch Pattern Strings
	trigger	Trg;		//List of Triggers
	int			Ani[][] =	//Door Animation Table
		// Opng| Open| Clsn| Clos|
		{{   -1,   -1,   -1,   -1},
		{    -1,   -1,   -1,   -1}};
	
	Update()
	{
		switch( Ste )
		{
			case "Opening";
				//Logic
				//Animation
				//Sound
				break;
			case "Open";
				//Logic
				//Animation
				//Sound
				break;
			case "Closing";
				//Logic
				//Animation
				//Sound
				break;
			case "Closed";
				//Logic
				//Animation
				//Sound
				break;
		default;
		}
	}
	Use()
	{
		//*Check Switch Type
		switch( Swt )
		{
			case "Toggle";
				//*Compare Trigger States To Door Switch Type
				for( trigger DorTrg; trigger this.Trg )
				{
					//*Check Door State
					if( DorTrg.Ste == "Activated" )
					{
						//Set State to Next in Switch Pattern
						typeid( this )( Pat[int( Pat[0] )] );
						
						//Rotate Switch Pattern
						if( Pat[0] < Pat.Length() - 1 )
						{
							Pat[0] = String( int( Pat[0] ) + 1 );
						}
						else if( int( Pat[0] ) > Pat.Length() - 1 )
						{
							Pat[0] = "1";
						}
						break;
					}
				}
				break;

			case "And";
				String	TrgSte[];
				
				for( trigger DorTrg; trigger Trg )
				{
					//*Compare Trigger States
					
				}
				break;

			case "Or";
				break;
		default;
		}
	}
	Open()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Close()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Remove()
	{
		Super.Remove();
		DorCnt.Remove( this );
	}


private:
	door		DorCnt;		//List of Doors

	Create( ISceneNode DNde, string DNam, string DSte, int DAni[][], vector3df DVel )
	{
		Super.Create( DNde, DNam, DSte, DAni, DVel );
		door D = new door;
		
		ListAddLast( Lst, D );
		ListAddLast( DorLst, D );
		return D;
	}
};

class elevator : public prop
{
public:
	vector3df				PntA;	//Point A of Path
	vector3df				PntB;	//Point B of Path
	ISceneNodeAnimator	Pth;	//Elevator Path
	float					Spd;	//Speed of Elevator
	string					Swt;	//Switch Type
	string					Pat[];	//Current Switch, Switch Pattern Strings
	trigger				Trg;	//List of Triggers
	
	Update()
	{
		switch Ste;
		{
			case "Top";
				//Logic
				//Animation
				//Sound
				break;
			case "Raising";
				//Logic
				//Animation
				//Sound
				break;
			case "Bottom";
				//Logic
				//Animation
				//Sound
				break;
			case "Lowering";
				//Logic
				//Animation
				//Sound
				break;
		}
	}


	Use()
	{
		if( Ste == "Top" )
		{
			this.Lower();
		}
		else if( Ste == "Bottom" )
		{
			this.Raise();
		}
	}
	Lower()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Raise()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Remove()
	{
		Super.Remove();
		ElvCnt.Remove( this );
	}

private:
	Create( ISceneNode ENde, string ENam, string ESte, vector3df EPntA, vector3df EPntB, ISceneNodeAnimator EPth, float ESpd )
	{
		elevator	E	= new elevator;
		
		E.Nde	= ENde;
		E.Nam	= ENam;
		E.Ste	= ESte;
		E.PntA	= EPntA;
		E.PntB	= EPntB;
		E.Pth	= EPth;
		E.Spd	= ESpd;
		
		ListAddLast( Cnt, E );
		ListAddLast( ElvCnt, E );
		return E;
	}
};

class conveyor : public prop
{
public:
	float		Spd		//Speed of Conveyor
	string		Swt		//Switch Type
	string		Pat[]	//Switch Pattern On, Reverse, Off
	trigger	Trg		//List of Triggers
	
	Use()
	{
		if( Ste == "Forward" )
		{
			this.Deactivate();
		}
		else if( Ste == "Halted" )
		{
			this.Activate()
		}
	}
	Activate()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Reverse()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Deactivate()
	{
		//Logic
		//Sound
		//Special Effects
	}
	Remove()
	{
		Super.Remove();
		CnvCnt.Remove( this );
	}

private:
	conveyor	CnvCnt	//List of Conveyors
	
	Update()
	{
		switch Ste;
			case "Forward";
				//Logic
				//*Check Switch Type
				
				//Animation
				//Sound
				
			case "Halted";
			 	//Logic
				//*Check Switch Type
				
				//Animation
				//Sound
				
			case "Reversed";
				//Logic
				//*Check Switch Type
				
				//Animation
				//Sound
		default;
	}
	Create( ISceneNode CNde, string CNam, string CSte, float CSpd )
	{
		conveyor	C	= new conveyor;
		
		C.Nde	= CNde;
		C.Nam	= CNam;
		C.Ste	= CSte;
		C.Spd	= CSpd;
		
		ListAddLast( Lst, C );
		ListAddLast( CnvLst, C );
		return C;
	}
};

class spawn : public prop
{
public:
	void		Obj;	//List of Objects to Spawn
	string		Swt;	//Switch Type
	list		Trg;	//List of Triggers
	
	Use( vector3df Pos, vector3df Rot, vector3df Scl, stringw Nam )
	{
		//Spawn
		//*Create Objects in Object List
		for each( void Spw in Obj )
		{
			if( Spw == class( user )) //User Node
				user( Spw )->Initialize( Pos, Rot );
			void( Spw );
			//*Add Created Object to Parent Trigger Child Counter
		}
	}
	Remove()
	{
		Super.Remove();
		SpwCnt.Remove( this );
	}
private:
	list		SpwCnt;	//List of Spawn Nodes
	
	Update()
	{	
	}
	Create( ISceneNode SNde, string SNam, string SSte, void SObj )
	{
		spawn	S	= new spawn;
		
		S.Nde = SNde;
		S.Nam = SNam;
		S.Ste = SSte;
		S.Obj = SObj;
		
		prop::Cnt.push_back( S );
		SpwCnt.push_back( S );

		return S;
	}
};

class prop : public trigger
{
public:
	string		Typ			//Type ( And, Or, Not ) null is Child Type
	string		Sty			//Style ( Press, select, Area ) null is Automatic
	string		Lok			//Key Flag, null is Unlocked
	int			Dly			//Activate Delay Milliseconds, - is Auto Activated
	int			DlyCnt		//Activate Delay Counter
	int			Tmr			//Deactivate Timer Milliseconds, - is Auto Deactivated
	int			TmrCnt		//Deactivate Timer Counter
	int			Cld			//Child Flag, -1 is None
	list		CldCnt		//List of Children
	prop		Prp			//List of props
	trigger	TrgLst[]	//Array of Triggers
	
	Update()
	{
		//Check State
		switch( Ste )
		{
			case "Activated";
				//Subtract Deactivate Timer
				if( TmrCnt > 0 ) TmrCnt -= 1000 / LastFPS;
				//Auto Deactivate Trigger
				if( TmrCnt =< 0 && Tmr < 0 ) TmrCnt = TmrCnt - TmrCnt * 2;
				break;

			case "Deactivated";
				//Subtract Activate Delay
				if( DlyCnt > 0 ) DlyCnt -= 1000 / LastFPS;
				//Auto Activate Trigger
				if( DlyCnt =< 0 && Dly < 0 ) DlyCnt = DlyCnt - DlyCnt * 2;
				break;

		default;
		}

		//*Check Style
		if( Sty == "null" )
		{
			this.Use();
		}
	}
	Use()
	{
		//*Check Counters, Keys, and Children
		if( TmrCnt =< 0 && DlyCnt =< 0 &&
			( Key.Contains( Lok ) || Lok == "" ) &&
			( Cld == -1 || CldCnt.Count() == Cld )
		{
			//Check Type Group
			if( Typ )
			{
				string	TrgSte;	//Trigger States
				
				//Check Conditional Triggers
				for each( trigger	T; TrgArr )
				{
					TrgSte = TrgSte + T.Ste;
				}
				
				//*Check Condition Type
				switch( Typ )
				{
				case "And";
					//*All Triggers Activated
					if( TrgSte.Contains( "Deactivated" ) == false )
					{
						//Trigger Triggers
						for each( trigger	T; TrgLst )
						{
							//Trigger Trigger
							T.Use();
						}
						//Trigger props
						for each( void O; Prp )
						{
							//*Trigger prop
							typeid.FindMethod( Use ).Invoke( O );
						}
					}
					break;

				case "Or";
					//*Any Trigger Activated
					//Trigger Triggers
					for each( trigger	T; this.TrgLst )
					{
						//Trigger Trigger
						T.Use();
					}
					//Trigger props
					for each( Prp; void O )
					{
						//*Trigger prop
						typeid.FindMethod( Use ).Invoke( O );
					}
					break;
				case "Not";
					//*All Triggers Deactivated
					if( TrgSte.Contains( "Activated" ) == false )
					{
						//Trigger Triggers
						for each( trigger T; TrgArr )
						{
							//Trigger Trigger
							T.Use();
						}
						//Trigger props
						for each( void O; Prp )
						{
							//*Trigger prop
							typeid.FindMethod( Use ).Invoke( O );
						}
					}
					break;
				default;
				}
			}
			else
			{
				//Trigger Triggers
				for each( trigger T; TrgArr )
				{
					//Trigger Trigger
					T.Use();
				}
				
				//Trigger props
				for each( void O; Prp )
				{
					//Trigger prop
					typeid.FindMethod( Use ).Invoke( O );
				}
			}
			
			//Set Trigger State
			if( Ste == "Deactivated" )
			{
				Ste = "Activate";
			}
			else if( Ste == "Activated" )
			{
				Ste = "Deactivate";
			}
			
			//Set Activate Delay
			if( DlyCnt =< 0 && Dly > -1 )
			{
				DlyCnt = Dly;
			}
			else if( Dly =< 0 )
			{
				DlyCnt = +Dly;
			}
			
			//Set Deactivate Timer
			if( TmrCnt =< 0 && Tmr > -1 )
			{
				TmrCnt = Tmr;
			}
			else if( Tmr < 0 )
			{
				TmrCnt = +Tmr;
			}
		}
	}
	Remove()
	{
		Super.Remove();
		TrgCnt.Remove( this );
	}

private:
	list	TrgCnt	//List of Triggers
	
	Create( ISceneNode TNde, String TNam, String TSte, String TTyp, Stirng TSty, String TLok, int TDly, int TTmr, void TPrp )
	{
		trigger	T	= new trigger;
		
		T.Nde	= TNde;	//Node
		T.Nam	= TNam;	//Name
		T.Ste	= TSte;	//State
		T.Lok	= TLok;	//Key
		T.Typ	= TTyp;	//Type
		T.Sty	= TSty;	//Style
		T.Dly	= TDly;	//Activate Delay
		T.Tmr	= TTmr;	//Deactivate Timer
		T.Prp	= TPrp;	//List of props
		

		//ListAddLast( Lst, T );
		//ListAddLast( TrgLst, T );
		return T;
	}
};

class portal : public prop
{
public:
private:
}

class collectable
{
public:
	ISceneNode	Nde;	//Collecable Node
	string		Nam;	//Name of Collecable
	string		Ani;	//Animation of Collectable
	string		Ste;	//State of Collectable
	int			Sty;	//Style of Collectable
	int			Amt;	//Ammount Within Collectable
	float		Hzd;	//Damage to User
	vector3df	Vel;	//Collectable Velocity
	
	Update()
	{
		switch( Ste )
		{
			case "Appear";
				break;
			case "Active";
				break;
			case "Static";
				break;
			case "Disappear";
				break;
		default;
		}

		vector3df	Pos	= Nde.getPosition();
		if( Vel ) Nde.setPosition( Pos.operator + Vel );

		return collectable;
	}	
	Pickup()
	{
		//Grab Users Hand
		//Apply User Statistics
		//Remove Reference
		
	}
	Remove()
	{
		Nde.Remove();
		Cnt.Remove( this );
	}
private:
	list				Count;	//List of Collectables
	ITriangleselector	Slc;	//Triangle selector

	Create( ISceneNode CNde, string CNam, string CAni, int CSty, int CAmt, float CHzd )
	{
		collectable	C	= new collectable;
		
		C.Nde	= CNde;
		C.Nam	= CNam;
		C.Ani	= CAni;
		C.Sty	= CSty;
		C.Amt	= CAmt;
		C.Hzd	= CHzd;
		
		ListAddLast( Cnt, C );
		return C;
	}
};

class effect
{
protected:
	ISceneNode	Nde;	//Effect Node
	string		Ste;	//State of Effect
	string		Nam;	//Name of Effect
	int			Lfe;	//Current LifeTime of Effect
	
	Remove()
	{
		Nde.Remove();
		Cnt.Remove( this );
	}
private:
	list		Cnt;	//List of Effects
		
	Update()
	{		
	}
	Create()
	{
	}
};

class projectile : public effect
{
public:
	int				Tpe;		//Projectile Type
	IAnimatedMesh	Msh;		//Projectile Mesh
	vector3df		Vel;		//Projectile Velocity
	vector3df		Dsp;		//Displacement from Last Position
	vector3df		LstLstPos;	//Last Last Position
	vector3df		LstPos;		//Last Position
	int				Ani[];		//Animation: First Frame, Last Frame
	
	Update()
	{
		for( projectile P	= EachIn projectile.Cnt )
		{
			//Update Position
			P.LstPos = P.Nde.getAbsolutePosition();	//Set Last Position
			P.Nde.SetPosition( P.Nde.getAbsolutePosition().Plus( P.Vel ));	//Set Current Position
			
			//Update Rotation
			
			//Update Collision
			if( P.LstPos )
			{
				//Test Bounding Box Collision
				Local Pth:line3df			= line3df( P.LstPos, P.Nde.getAbsolutePosition());
				Local ColRad:float		= Pth.GetStart().getDistanceFrom( Pth.GetEnd());
				Local PrjPos:vector3df	= P.Nde.getAbsolutePosition();
				//Local Colide:ISceneNode = smgr.getSceneCollisionManager().getSceneNodeFromRayBB( Path ) //Projectile Collision
				
				//Projectile Expire
				//if( P.Nde.getAbsolutePosition().getDistanceFrom( user.Nde.getAbsolutePosition()) > float( projectile.PrjInf[4][P.Style] ))
				//	P.Remove()
				//	
				//else if( ColRad )
				if( P.Lfe <= 0 )
				{
					P.Remove();
				//else if( Colide )
				//	for Local D:Debris = EachIn Debris.Count
				//		if( ColRad < D.Node.getAbsolutePosition().getDistanceFrom( PPos ))
				//			if( Colide.Compare( D.Node ))
				//				Local DebrisMesh:IAnimatedMesh = Scene.getMesh( "media/Asteroid1.ms3d" ) //Debris Mesh
				//				Local selector:ITriangleselector = Scene.createTriangleselector( DebrisMesh.getMesh( 0 ), D.Node ) //Triangle selector
				//				Local Intersection:vector3df = vector3df<s32>.Create() //Collision Vector
				//				Local Tri:triangle3df = triangle3df.Create() //Collision Triangle

				//				D.Node.setTriangleselector( selector ) //Add Triangle selector as Child

				//				//Test Mesh Collision
				//				if( Scene.getSceneCollisionManager().getCollisionPoint( Path, selector, Intersection, Tri ))
				//					P.Colide( D, Colide.getAbsolutePosition()) //Problem with Collide Method?
				//					P.Colide( Intersection )
				//				D.Remove()

				//				break;
				//			}
				//		}
				//	}
				}
				else
				{
					//Update Attributes
					P.Lfe -= int( 1000 / LastFPS );	//Update LifeTime
					P.Ste = null;						//Update State
				}
			}
			
			//Local Path:line3df
			//Path.setLineFromVects( P.LastPos, P.Node.getAbsolutePosition()) //Projectile Path
			//Local Colide:ISceneNode = Scene.getSceneCollisionManager().getSceneNodeFromRayBB( Path ) //Projectile Collision
			//
			//if( Colide.getType() == ESNT_ANIMATED_MESH )
			//	for Local D:Debris = EachIn Debris.Count
			//		if( Colide.Compare( D.Node ) Then D.Remove()
			//	}
			//}
			
			//line.setLineFromVects(CAMERA.getPosition(), ..
			//	line.getStart().Plus((CAMERA.getTarget().Minus(line.getStart())).normalize().Mult(1000.0)))
			//
			//if( ( Scene.getSceneCollisionManager().getCollisionPoint( ..
			//	line, selector, intersection, tri ))
			//	
			//	bill.setPosition(intersection)
			//	
			//	driver.SetTransform(ETS_WORLD,matrix4.create())
			//	driver.setMaterial(material)
			//	driver.draw3DTriangle(tri,_SCOLOR(0,255,0,0))
			//Endif
			//
			//Local Path:line3df = line3df( P.LastPos, P.Node.getAbsolutePosition() )
			//
			//for Local D:Debris = EachIn Debris.Count
			//	Local Mesh:IAnimatedMesh = Scene.getMesh( "media/Asteroid1.ms3d" )
			//	
			//	if( D.Node.getBoundingBox().intersectsWithLine( Path ))
			//		BoundingBox Collision
			//		Local selector:ITriangleselector = Scene.createTriangleselector( Mesh.getMesh( 0 ), D.Node ) //Triangle selector
			//		Local Intersection:vector3df = vector3df<s32>.Create() //Collision Vector
			//		Local Tri:triangle3df = triangle3df.Create() //Collsion Triangle
			//		
			//		D.Node.setTriangleselector( selector )
			//		
			//		if( Scene.getSceneCollisionManager().getCollisionPoint( Path, selector, Intersection, Tri ))
			//			Mesh Collision
			//			P.Colide( Intersection )
			//			D.Destroy(  )
			//		}
			//	}
			//}
		}
	}
	Destroy()
	{
		
	}
	Remove()
	{
		Nde.Remove()
		Cnt.Remove( this )
	}

private:	
	string		PrjInf[][]	=	//Projectile Info Table [Nam][Attribute]
		//     Name| Speed|   Rate|   Fall|   Trail|  Sight|  Shake|   Steady| Hazard| Damage|   Life|
		//         |      |    Ms.|       |    Bool| Radius|    Use|     /Ms.|    Hp.| Radius|    Ms.|
		{{"Trw Str",   "7",  "500",  "0.2", "False",   "16", "1.50", "0.0125",    "5",    "0", "2000"},
		{ "Trw Knf",   "5", "1000",  "0.5", "False",   "24",    "2", "0.0125",    "7",    "0", "1700"},
		{ "Grp Hok",  "-1",    "0",  "0.5",  "True",    "0",    "0",      "0",  "0.5",    "0",     ""},
		{ "Zip Lin",  "-1",    "0",  "0.5",  "True",    "0",    "0",      "0",  "0.5",    "0",     ""}}
	projectile	Cnt;			//List of Projectiles
	
	Create( int PrjTpe, vector3df Pos, vector3df Rot, vector3df Vel )
	{	
	}
	Use( int PrjTpe )
	{
		projectile		P	= new projectile;			//New Projectile
		IAnimatedMesh	M	= smgr.getMesh( "media/" + projectile.PrjInf[PrjTpe][0] + ".ms3d" );    //Projectile Mesh
		
		//Check Projectile Mesh
		if( M && M.IsValid() == true )
		{
			//Create Projectile
			P.Msh	= M;	//Projectile Mesh
			P.Nde	=		//Projectile Node
				smgr.addAnimatedMeshSceneNode( P.Msh, null, null, user.Nde.getAbsolutePosition(), user.Nde.GetRotation());
		}

		//Projectile Mesh Invalid
		else
		{
			//Display Error Message
			cout << "Projectile Mesh Invalid" << endl;
			break;
		}
		
		//Check Projectile Node
		if( P.Nde.IsValid() == true )
		{
			cout << "Prj Nde Succeded" << endl;
			//Tracer Throw
			if( projectile.PrjInf[PrjTpe][4] == "False" )
			{
				cout << "Prj Tracer Succeded" << endl;
				
				P.Nde.setMaterialType( EMT_TRANSPARENT_ADD_COLOR );	//Material Type
				P.Nde.setMaterialFlag( EMF_LIGHTING, false );			//Material Lighting
				
				//Set Velocity
				matrix4	M1;
				//matrix4	M2;
				matrix4	M3;
				vector3df	PrjFwd	= vector3df<s32>( 0, 0, float( projectile.PrjInf[PrjTpe][1] ));
				//vector3df	Acc	= vector3df<s32>( 0, RandRange( -ActAcc[Amm[2]] / 2 * 100, ActAcc[Eqp[0]] / 2 * 100 ) / 100, RandRange( 0, 359 )); //Accuracy
				
				P.LstPos	= ( P.Nde.getAbsolutePosition().Plus( vector3df<s32>( 0, 40, 0 )));	//Set Last Position
				M1.setRotationDegrees( user.Nde.GetRotation());
				//M2.setRotationDegrees( Acc());
				//M1.MultEq( M2 );
				P.Nde.SetRotation( M1.getRotationDegrees());	//Set Rotation
				M3.makeIdentity();
				M3.setRotationDegrees( P.Nde.GetRotation());
				M3.transformVect( PrjFwd )
				P.Vel = PrjFwd.Plus( user.Vel )	//Set Velocity
			}

			//Rope Throw
			else if( projectile.PrjInf[PrjTpe][4] == "True" )
			{
				cout << "Prj Rope Succeded" << endl;
				
				P.Nde.setMaterialType( EMT_SOLID );				//Material Type
				P.Nde.setMaterialFlag( EMF_LIGHTING, true );	//Material Lighting
				
				//Set Velocity
				matrix4	M1;
				//matrix4	M2;
				matrix4	M3;
				vector3df	PrjFwd	= vector3df<s32>( 0, 0, float( projectile.PrjInf[PrjTpe][1] ));
				//vector3df	Acc	= vector3df<s32>( 0, RandRange( -ActAcc[Amm[2]] / 2 * 100, ActAcc[Eqp[0]] / 2 * 100 ) / 100, RandRange( 0, 359 )); //Accuracy
				
				P.LstPos	= ( P.Nde.getAbsolutePosition().Plus( vector3df<s32>( 0, 40, 0 )));	//Set Last Position
				M1.setRotationDegrees( user.Nde.GetRotation());
				//M2.setRotationDegrees( Acc );
				//M1.MultEq( M2 );
				P.Nde.SetRotation( M1.getRotationDegrees());	//Set Rotation
				M3.makeIdentity();
				M3.setRotationDegrees( P.Nde.GetRotation());
				M3.transformVect( PrjFwd );
				P.Vel	= PrjFwd;	//Set Velocity
			}
			
			//P.Nde.setMaterialTexture( 0, driver.getTexture( "media/" + projectile.PrjInf[PrjTpe][0] + " Mat.tga" )) //Projectile Texture
			if( Amm[3] == 0 )			//Use Rate
			{	
				//Set Weapon Use Rate
				ActTmr[0] = int( WpnInf[Eqp[0]][2] );
			}
			else if( Amm[3] == 1 )
			{
				//Set Item Use Rate
				ActTmr[1] = int( EqpInf[Eqp[1]][2] );
			}
			P.Tpe	= PrjTpe;						//Set Projectile Type
			P.Lfe	= int( PrjInf[PrjTpe][10] );	//Set Initial LifeTime
			P.Ste	= null;							//Set Initial State
			if( Amm[3] == 0 ) Amm[1] -=1;			//Subtract Round
			if( Amm[3] == 1 ) Amm[2] -=1;			//Subtract Ammount
			AphInd[1]	= 100;						//Apply Rounds Indicator
			
			ListAddLast( Lst, P );				//Insert Projectile
			ListAddLast( Cnt, P );
			
			//Subtract Accuracy
			//if( ActAcc[Amm[2]] < float( projectile.PrjInf[Eqp[0]][5] ) Then ActAcc[Amm[2]] += float( projectile.PrjInf[Eqp[0]][7] )
			//if( ActAcc[Amm[2]] < float( projectile.PrjInf[Eqp[1]][5] ) Then ActAcc[Amm[2]] += float( projectile.PrjInf[Eqp[1]][7] )
		}

		//Projectile Node Invalid
		else
		{
			//Display Error Message
			cout << "Projectile Node Invalid" << endl;
			break;
		}
		cout << P.Vel.getX() << ", " << P.Vel.getY() << ", " << P.Vel.getZ() << endl;
		//return P
	}
};

class particle : public effect
{
public:
	vector3df	Vel;		//Particle Velocity
	int			Tmr;		//Particle Expiration Ms.

	Remove()
	{	
	}
private:
	particle	PrtCnt;		//List of Particles
	
	Update()
	{
	}
	Create()
	{	
	}
};


//* Temporary Debug Code
//map.Initialize( "rok.bsp", vector3df<s32>( 0, 0.50, 0 ), "./media/heightmap.bmp", "./media/detailmap3.jpg", "./media/terrain-texture.jpg", vector3df( 40.f, 5.f, 40.f ));
//user.Initialize( vector3df<s32>( 300, 800, 30 ), IAnimatedMesh( smgr.getMesh( "media/NinjaTest.ms3d" )));
//user.Nde.setMaterialTexture( 0, driver.getTexture( "media/clan_killer.bmp" ));
//RPGCamera.Create( vector3df<s32>( 300, 800, 30 ), user.Nde());